/**
 * Copyright (c) 2018 人人开源 All rights reserved.
 * <p>
 * https://www.renren.io
 * <p>
 * 版权所有，侵权必究！
 */

package com.codegen.controller;

import com.codegen.entity.*;
import com.codegen.service.SysGeneratorService;
import com.codegen.service.TableService;
import com.codegen.utils.GenUtils;
import com.codegen.utils.PageUtils;
import com.codegen.utils.Query;
import com.codegen.utils.R;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotBlank;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipOutputStream;

/**
 * 代码生成器
 *
 * @author Mark sunlightcs@gmail.com
 */
@Slf4j
@RestController
@RequestMapping("/generator")
public class GeneratorController {
    @Autowired
    private SysGeneratorService sysGeneratorService;

    @Autowired
    private TableService tableService;

    /**
     * 常用的枚举
     */
    @RequestMapping("/enums")
    public R schemaList(@NotBlank String type) {
        String className = "com.codegen.enums." + StringUtils.capitalize(type);
        try {
            Class<?> clz = Class.forName(className);
            if (!clz.isEnum()) {
                return R.error();
            }
            return R.ok().put("data", clz.getEnumConstants());
        } catch (Exception e) {
            log.error("常用的枚举", e);
            return R.error();
        }
    }

    /**
     * 列表
     */
    @ResponseBody
    @RequestMapping("/dbtable/list")
    public R dbtableList(@RequestParam Map<String, Object> params) {
        PageUtils pageUtil = sysGeneratorService.queryList(new Query(params));
        return R.ok().put("page", pageUtil);
    }

    @ResponseBody
    @RequestMapping("/dbtable/colums")
    public R dbtableColums(String tableName) {
        List<Map<String, String>> list =sysGeneratorService.queryColumns(tableName);
        return R.ok().put("colums", list);
    }

    /**
     * 生成代码
     */
    @RequestMapping("/code")
    public void code(String tables, HttpServletResponse response) throws IOException {
        byte[] data = sysGeneratorService.generatorCode(tables.split(","));

        response.reset();
        response.setHeader("Content-Disposition", "attachment; filename=\"renren.zip\"");
        response.addHeader("Content-Length", "" + data.length);
        response.setContentType("application/octet-stream; charset=UTF-8");

        IOUtils.write(data, response.getOutputStream());
    }

    /**
     * 生成代码到压缩包进行下载
     */
    @PostMapping("/generateCode2Zip/{tableId}")
    public void generateCode2Zip(@PathVariable Integer tableId, @RequestBody TableGenParam genParam, HttpServletResponse response) {
        TableVo table = tableService.selectOneByTableId(tableId);
        TableGenSchema schema = new TableGenSchema();
        BeanUtils.copyProperties(table, schema);
        BeanUtils.copyProperties(genParam, schema);
        schema.setGenParam(genParam);
        try (ZipOutputStream zip = new ZipOutputStream(response.getOutputStream())) {
            // 生成代码
            initTableRefs(table.getProjectId(), schema);
            GenUtils.generatorCodeToZip(schema, zip);
            response.setHeader("Content-Disposition", "attachment; filename=\"code.zip\"");
            response.setContentType("application/octet-stream; charset=UTF-8");
        } catch (Exception e) {
            log.error("生成代码异常", e);
        }
    }

    /**
     * 生成代码到压缩包进行下载
     */
    @PostMapping("/batchGenCode2Zip")
    public void batchGenerateCode2Zip(String tableIds, @RequestBody TableGenParam genParam, HttpServletResponse response) {
        String[] tableIdArray = tableIds.split(",");
        try (ZipOutputStream zip = new ZipOutputStream(response.getOutputStream())) {
            for (String tableIdStr : tableIdArray) {
                TableVo table = tableService.selectOneByTableId(Integer.parseInt(tableIdStr));
                TableGenSchema schema = new TableGenSchema();
                BeanUtils.copyProperties(table, schema);
                BeanUtils.copyProperties(genParam, schema);
                schema.setGenParam(genParam);
                initTableRefs(table.getProjectId(), schema);
                // 生成代码
                GenUtils.generatorCodeToZip(schema, zip);
            }
            response.setHeader("Content-Disposition", "attachment; filename=\"code.zip\"");
            response.setContentType("application/octet-stream; charset=UTF-8");
        } catch (Exception e) {
            log.error("生成代码异常", e);
        }
    }

    /**
     * 生成代码到指定的目录（非本地目录，是本应用服务器的目录）
     */
    @PostMapping("/generateCode2Path/{tableId}")
    public R generateCode2Path(@PathVariable Integer tableId, @RequestBody TableGenParam genParam) {
        TableVo table = tableService.selectOneByTableId(tableId);
        TableGenSchema schema = new TableGenSchema();
        BeanUtils.copyProperties(table, schema);
        BeanUtils.copyProperties(genParam, schema);
        schema.setGenParam(genParam);
        try {
            initTableRefs(table.getProjectId(), schema);
            GenUtils.generatorCodeToPath(schema);
            return R.ok("生成完成");
        } catch (Exception e) {
            log.error("生成失败", e);
            return R.error("生成完成");
        }
    }

    /**
     * 生成代码到指定的目录（非本地目录，是本应用服务器的目录）
     */
    @PostMapping("/batchGenCode2Path")
    public R batchGenCode2Path(String tableIds, @RequestBody TableGenParam genParam) {
        try {
            String[] tableIdArray = tableIds.split(",");
            for (String tableIdStr : tableIdArray) {
                TableVo table = tableService.selectOneByTableId(Integer.parseInt(tableIdStr));
                TableGenSchema schema = new TableGenSchema();
                BeanUtils.copyProperties(table, schema);
                BeanUtils.copyProperties(genParam, schema);
                schema.setGenParam(genParam);
                initTableRefs(table.getProjectId(), schema);
                GenUtils.generatorCodeToPath(schema);
            }
            return R.ok("生成完成");
        } catch (Exception e) {
            log.error("生成失败", e);
            return R.error("生成失败");
        }
    }

    private void initTableRefs(Integer projectId, TableGenSchema schema) {
        List<TableRef> refs = schema.getTableRefs();
        for (TableRef ref : refs) {
            String tableName = ref.getTableName();
            Table table = tableService.selectByTableName(projectId, tableName);
            ref.setRefTable(table);
        }
    }
}
